﻿using System;
using System.Collections.Generic;
using Serilog;

using net.vieapps.Components.WebSockets;
using net.vieapps.Components.Utility;
using net.vieapps.Components.WebSockets.Exceptions;
// using System.Net.WebSockets;

using System.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Microsoft.EntityFrameworkCore;
using WebSocketSharp.Net.WebSockets;
using WebSocketSharp.Server;

using Autofac;

namespace CoworkspaceAdmin.Server
{
    using CoworkspaceAdmin.Controller;

    public enum ProcessingMessageType
    {
        Data,
        Text
    }

    public class Client {

        static string UnAuthedToken = "{\"msg_type\":\"unlogin\"}";
        public bool IsAuthed { get; set; }
        string userID;
        string password;
        ManagedWebSocket ws;

        public ProcessingMessageType nextMessageType {get; set;} = ProcessingMessageType.Text;



        public Client(ManagedWebSocket s)
        {
            ws = s;
        }

        public void Reply(string msg)
        {
            if (ws is null) return;
            ws.SendAsync(msg, true);
        }

        public void ReplyUnAuthed()
        {
            Reply(UnAuthedToken);
        }


        public void Disconnect()
        {
            if (!(ws is null))
            {
                ws.CloseAsync(
                System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, 
                "", System.Threading.CancellationToken.None);
            }
        }
    }


    public class Server
    {
        WebSocket listenWs;
        Dictionary<Guid, Client> clients = new Dictionary<Guid, Client>();

        public Server()
        {
            Log.Information("Server create ...");
            listenWs = new WebSocket
            {
                OnError = (webSocket, exception) =>
                {
                    // your code to handle error
                },
                OnConnectionEstablished = (webSocket) =>
                {
                    // your code to handle established connection

                },
                OnConnectionBroken = (webSocket) =>
                {
                    // your code to handle broken connection
                },
                OnMessageReceived = (webSocket, result, data) =>
                {
                    // your code to handle received message
                    if (clients.ContainsKey(webSocket.ID))
                    {
                        Client client = clients[webSocket.ID];
                        if (client.IsAuthed)
                        {
                            switch(result.MessageType){
                                case System.Net.WebSockets.WebSocketMessageType.Text: {
                                    try
                                    {
                                        JObject obj = JObject.Parse(System.Text.Encoding.UTF8.GetString(data));
                                        MessageProcess(obj, ref client);    // may change client's states
                                        clients[webSocket.ID] = client;
                                    }
                                    catch (JsonReaderException e)
                                    {
                                        Log.Warning("Message is not Json Format: {0}", e);
                                    }
                                    break;
                                }
                                case System.Net.WebSockets.WebSocketMessageType.Binary: {
                                    if (client.nextMessageType == ProcessingMessageType.Text) return;
                                    if (result.EndOfMessage){
                                        client.nextMessageType = ProcessingMessageType.Text;
                                    }
                                    break;
                                }
                                case System.Net.WebSockets.WebSocketMessageType.Close: {
                                    break;
                                }
                                default:break;
                            }

                        
                            // todo
                            
                        }
                        else
                        {
                            client.ReplyUnAuthed();
                        }
                    }
                    else
                    {
                        Log.Warning("An websocket not managed in clients.");
                    }
                }
            };
        }

        public void Start()
        {
            if (!(listenWs is null))
            {
                listenWs.StopListen();
            }
            int port = Convert.ToInt32(ConfigurationManager.AppSettings.Get("ServerPort"));
            listenWs.StartListen(port);
        }

        public void Stop()
        {
            if (listenWs is null)
            {
                return;
            }
            listenWs.StopListen();
        }

        private void MessageProcess(JObject jObject, ref Client ws)
        {
            
        }

        public void test()
        {
            // var manager = Program.GetSingletonService<ICompanyManager>();
            // manager.RemoveCompany("in service");
            // try{
            //     var e = JObject.Parse("{abc:der");
            // }catch{
            //     Log.Debug("UnParse message.");
            // }
            using (var scope = Program.Container.BeginLifetimeScope()){
            var ctx = scope.Resolve<Models.postgresContext>();
            Log.Debug("ctx 1: {0}", ctx);
            ctx.User.Remove(new Models.User(){
                Company = "成都三医智汇科技有限公司",
                Id = "123",
                Name = "like"
            });
            ctx.SaveChanges();
            }
        }
    }
}
